﻿using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Brushes;
using Microsoft.Graphics.Canvas.Effects;
using Microsoft.Graphics.Canvas.Geometry;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel.Email.DataProvider;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Xaml.Shapes;
using 纸片人.AttributeUsageFloder;

// https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板

namespace 纸片人.PageViews
{
    [PageTypeAttribute("cpu", "贝塞尔曲线")]
    /// <summary>
    /// 可用于自身或导航至 Frame 内部的空白页。
    /// </summary>
    public sealed partial class BesselPage : Page
    {
        /// <summary>
        /// 所有控制点的位置
        /// </summary>
        List<Bessel> listBessel = new List<Bessel>();
        //预览线点位置
        Bessel previewLine = new Bessel();

        bool isPreview = false;
        //是否完成了
        bool isComplate = false;
        //是否关闭了
        bool isClosure = false;

        BorderEffect gridTargetEffect;
        public BesselPage()
        {
            this.InitializeComponent();
            Init();
  

        }

        private void Init()
        {
            clear.Click += (s, e) =>
            {
                listBessel.Clear();
                canvas.Invalidate();
                isComplate = false;
                isClosure = false;

                CollapsedDragThumb();
            };

            complate.Click += (s, e) =>
             {
                 isComplate = true;
             };

            canvas.CreateResources += (s, e) =>
            {
                var target = new CanvasRenderTarget(canvas, new Size(100, 100));
                using (var ds = target.CreateDrawingSession())
                {
                    for (int x = 0; x < 2; x++)
                    {
                        for (int y = 0; y < 2; y++)
                        {
                            Color color = (x + y) % 2 == 0 ? Colors.White: Color.FromArgb(255, 219, 219, 219);
                            ds.FillRectangle(new Rect(x * 50, y * 50, 50, 50), color);
                        }
                    }
                }
                gridTargetEffect = new BorderEffect()
                {
                    Source = target,
                    ExtendY = CanvasEdgeBehavior.Wrap,
                    ExtendX = CanvasEdgeBehavior.Wrap,
                };
            };
        }

       

        /// <summary>
        /// 画
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void canvas_Draw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args)
        {
            using (var ds = args.DrawingSession)
            {
 

                // 画辅助先
                ds.DrawImage(gridTargetEffect);

                if (listBessel.Count > 0)
                {
                    CanvasPathBuilder path = new CanvasPathBuilder(sender);
                    CanvasPathBuilder line = new CanvasPathBuilder(sender);
                    Vector2 startPoint = listBessel[0].Vect;
                    line.BeginFigure(startPoint);
                    Vector2 previousVect = startPoint;
                    foreach (var item in listBessel)
                    {

                        line.AddCubicBezier(startPoint, item.LeftVect, item.Vect);
                        ds.FillRectangle(new Rect(item.Vect.X - 5, item.Vect.Y - 5, 10, 10), Colors.OrangeRed);
                        startPoint = item.RightVect;
                        previousVect = item.Vect;
                    }

                    if (isPreview && !isComplate)
                    {
                        path.BeginFigure(previousVect);
                        path.AddCubicBezier(startPoint, previewLine.LeftVect, previewLine.Vect);
                        ds.DrawLine(previewLine.LeftVect, previewLine.RightVect, Colors.Blue);
                        path.EndFigure(CanvasFigureLoop.Open);
                    }
                    else
                    {
                        if (!isComplate)
                        {
                            Vector2 endPoint = listBessel.Last().LeftVect;
                            ds.DrawLine(endPoint, startPoint, Colors.Blue);
                        }


                    }



                    line.EndFigure(CanvasFigureLoop.Open);
                    CanvasGeometry apple = CanvasGeometry.CreatePath(path);

                    CanvasGeometry lineGemetry = CanvasGeometry.CreatePath(line);


                    args.DrawingSession.DrawGeometry(apple, Colors.Gray);
                    args.DrawingSession.DrawGeometry(lineGemetry, Colors.Black);
                }
            }
        }

        bool isDown = false;

        Vector2 downPoint = new Vector2();

        Vector2 movePoint = new Vector2();


        Bessel selectPoint;

        /// <summary>
        /// 鼠标按下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void canvas_PointerPressed(object sender, PointerRoutedEventArgs e)
        {

            Point point = e.GetCurrentPoint(canvas).Position;

            downPoint.X = (float)point.X;
            downPoint.Y = (float)point.Y;

            if (isComplate)
            {
                foreach (var item in listBessel)
                {
                    if (downPoint.X > item.Vect.X - 5 && downPoint.X < item.Vect.X + 5 && downPoint.Y > item.Vect.Y - 5 && downPoint.Y < item.Vect.Y + 5)
                    {
                        selectPoint = item;

                        if (selectPoint == listBessel[0])
                        {
                            if (isClosure)
                            {
                                Bessel lastB = listBessel[listBessel.Count - 1];
                                VisibleDragThumb(lastB.LeftVect, selectPoint.Vect, selectPoint.RightVect, true, true);
                            }
                            else
                            {
                                VisibleDragThumb(selectPoint.LeftVect, selectPoint.Vect, selectPoint.RightVect, false, true);
                            }
                        }
                        else
                        {
                            VisibleDragThumb(selectPoint.LeftVect, selectPoint.Vect, selectPoint.RightVect, true, true);

                        }


                        return;
                    }
                }

                CollapsedDragThumb();
            }
            else
            {
                if (listBessel.Count > 1)
                {
                    Vector2 firstPoint = listBessel[0].Vect;
                    if (downPoint.X > firstPoint.X - 5 && downPoint.X < firstPoint.X + 5 && downPoint.Y > firstPoint.Y - 5 && downPoint.Y < firstPoint.Y + 5)
                    {
                        downPoint.X = firstPoint.X;
                        downPoint.Y = firstPoint.Y;
                        isClosure = true;
                    }
                }
                isDown = true;
            }



        }

        /// <summary>
        /// 鼠标移动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void canvas_PointerMoved(object sender, PointerRoutedEventArgs e)
        {
            Point point = e.GetCurrentPoint(canvas).Position;

            movePoint.X = (float)point.X;
            movePoint.Y = (float)point.Y;

            if (isDown)
            {
                isPreview = true;
                SetPreviewLine(downPoint, movePoint);
                canvas.Invalidate();
            }
        }

        void SetPreviewLine(Vector2 vect, Vector2 rightVect)
        {
            previewLine.Vect = vect;
            previewLine.RightVect = rightVect;
            previewLine.LeftVect = CalculationLeftPoint(vect, rightVect);
        }

        /// <summary>
        /// 鼠标弹起
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void canvas_PointerReleased(object sender, PointerRoutedEventArgs e)
        {
            if (!isComplate)
            {
                if (listBessel.Count > 1)
                {
                    Vector2 firstPoint = listBessel[0].Vect;
                    if (downPoint.X == firstPoint.X && downPoint.Y == firstPoint.Y)
                    {
                        isComplate = true;
                    }
                }

                isDown = false;
                isPreview = false;
                Bessel bessel = new Bessel();
                bessel.Vect = downPoint;
                bessel.RightVect = movePoint;
                bessel.LeftVect = CalculationLeftPoint(downPoint, movePoint);
                listBessel.Add(bessel);
                canvas.Invalidate();

            }

        }

        Vector2 CalculationLeftPoint(Vector2 vect, Vector2 rightVect)
        {
            Vector2 leftVect = new Vector2();


            leftVect.X = vect.X + (vect.X - rightVect.X);
            leftVect.Y = vect.Y + (vect.Y - rightVect.Y);

            return leftVect;
        }

        Vector2 CalculationRightPoint(Vector2 vect, Vector2 leftVect)
        {
            Vector2 rightVect = new Vector2();


            rightVect.X = vect.X + (vect.X - leftVect.X);
            rightVect.Y = vect.Y + (vect.Y - leftVect.Y);

            return rightVect;
        }



    
        private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            Thumb thumb = sender as Thumb;


            Vector2 lv = new Vector2();
            switch (thumb.Name)
            {
                case "leftThumb":
                    if (selectPoint == listBessel[0])
                    {
                        Bessel last = listBessel[listBessel.Count - 1];

                        lv.X = (float)(last.LeftVect.X + e.HorizontalChange);
                        lv.Y = (float)(last.LeftVect.Y + e.VerticalChange);
                        last.LeftVect = lv;
                        SetThumbPoint(leftThumb, lv);
                        setLinePoint(leftLine, lv, selectPoint.Vect);
                        canvas.Invalidate();
                    }
                    else
                    {
                        lv.X = (float)(selectPoint.LeftVect.X + e.HorizontalChange);
                        lv.Y = (float)(selectPoint.LeftVect.Y + e.VerticalChange);

                        selectPoint.LeftVect = lv;
                        selectPoint.RightVect = CalculationRightPoint(selectPoint.Vect, selectPoint.LeftVect);

                        setLinePoint(leftLine, lv, selectPoint.Vect);
                        setLinePoint(rightLine, selectPoint.Vect, selectPoint.RightVect);
                        SetThumbPoint(leftThumb, lv);
                        SetThumbPoint(rightThumb, selectPoint.RightVect);
                        canvas.Invalidate();
                    }
                    break;

                case "rightThumb":
                    lv.X = (float)(selectPoint.RightVect.X + e.HorizontalChange);
                    lv.Y = (float)(selectPoint.RightVect.Y + e.VerticalChange);

                    selectPoint.RightVect = lv;

                    if (!(selectPoint == listBessel[0]))
                    {
                        selectPoint.LeftVect = CalculationLeftPoint(selectPoint.Vect, selectPoint.RightVect);

                        setLinePoint(leftLine, selectPoint.LeftVect, selectPoint.Vect);
                        SetThumbPoint(leftThumb, selectPoint.LeftVect);

                    }


                    setLinePoint(rightLine, selectPoint.Vect, selectPoint.RightVect);



                    SetThumbPoint(rightThumb, selectPoint.RightVect);
                    canvas.Invalidate();

                    break;

                case "middThumb":

                    if (selectPoint == listBessel[0] && isClosure)
                    {
                        lv.X = (float)(selectPoint.LeftVect.X + e.HorizontalChange);
                        lv.Y = (float)(selectPoint.LeftVect.Y + e.VerticalChange);

                        Vector2 v = new Vector2();
                        Vector2 rv = new Vector2();

                        rv.X = (float)(selectPoint.RightVect.X + e.HorizontalChange);
                        rv.Y = (float)(selectPoint.RightVect.Y + e.VerticalChange);

                        v.X = (float)(selectPoint.Vect.X + e.HorizontalChange);
                        v.Y = (float)(selectPoint.Vect.Y + e.VerticalChange);

                        selectPoint.LeftVect = lv;
                        selectPoint.RightVect = rv;
                        selectPoint.Vect = v;

                        Bessel last = listBessel[listBessel.Count - 1];

                        last.Vect = new Vector2(last.Vect.X + (float)e.HorizontalChange, last.Vect.Y + (float)e.VerticalChange);
                        last.LeftVect = new Vector2(last.LeftVect.X + (float)e.HorizontalChange, last.LeftVect.Y + (float)e.VerticalChange);
                        last.RightVect = new Vector2(last.RightVect.X + (float)e.HorizontalChange, last.RightVect.Y + (float)e.VerticalChange);



                        setLinePoint(leftLine, last.LeftVect, last.Vect);
                        SetThumbPoint(leftThumb, last.LeftVect);

                        SetThumbPoint(middThumb, selectPoint.Vect);


                        setLinePoint(rightLine, selectPoint.Vect, selectPoint.RightVect);
                        SetThumbPoint(rightThumb, selectPoint.RightVect);
                        canvas.Invalidate();
                    }
                    else
                    {
                        lv.X = (float)(selectPoint.LeftVect.X + e.HorizontalChange);
                        lv.Y = (float)(selectPoint.LeftVect.Y + e.VerticalChange);

                        Vector2 v = new Vector2();
                        Vector2 rv = new Vector2();

                        rv.X = (float)(selectPoint.RightVect.X + e.HorizontalChange);
                        rv.Y = (float)(selectPoint.RightVect.Y + e.VerticalChange);

                        v.X = (float)(selectPoint.Vect.X + e.HorizontalChange);
                        v.Y = (float)(selectPoint.Vect.Y + e.VerticalChange);

                        selectPoint.LeftVect = lv;
                        selectPoint.RightVect = rv;
                        selectPoint.Vect = v;


                        setLinePoint(leftLine, selectPoint.LeftVect, selectPoint.Vect);
                        setLinePoint(rightLine, selectPoint.Vect, selectPoint.RightVect);
                        SetThumbPoint(leftThumb, selectPoint.LeftVect);
                        SetThumbPoint(rightThumb, selectPoint.RightVect);
                        SetThumbPoint(middThumb, selectPoint.Vect);
                        canvas.Invalidate();
                    }



                    break;


            }

        }


        void SetThumbPoint(Thumb thumb, Vector2 point)
        {
            thumb.Translation = new Vector3(point.X - 5, point.Y - 5, 0);

        }
        void setLinePoint(Line line, Vector2 v1, Vector2 v2)
        {
            line.X1 = v1.X;
            line.Y1 = v1.Y;
            line.X2 = v2.X;
            line.Y2 = v2.Y;
        }


        /// <summary>
        /// 显示拖动控件
        /// </summary>
        void VisibleDragThumb(Vector2 lv, Vector2 v, Vector2 rv, bool ls, bool rs)
        {
            SetThumbPoint(leftThumb, lv);
            SetThumbPoint(middThumb, v);
            SetThumbPoint(rightThumb, rv);
            setLinePoint(leftLine, lv, v);
            setLinePoint(rightLine, v, rv);
            leftThumb.Visibility = ls ? Visibility.Visible : Visibility.Collapsed;
            rightThumb.Visibility = rs ? Visibility.Visible : Visibility.Collapsed;
            rightLine.Visibility = leftLine.Visibility = middThumb.Visibility = Visibility.Visible;
        }
        //
        void CollapsedDragThumb()
        {
            rightLine.Visibility = leftLine.Visibility = leftThumb.Visibility = middThumb.Visibility = rightThumb.Visibility = Visibility.Collapsed;
        }


    }


    public class Bessel
    {

        public Vector2 Vect { get; set; }
        public Vector2 LeftVect { get; set; }
        public Vector2 RightVect { get; set; }
        /// <summary>
        /// 计算贝塞尔每一个点的位置
        /// 
        /// </summary>
        /// <param name="t"></param>
        /// <param name="p0"></param>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <param name="p3"></param>
        /// <returns></returns>
        public Vector2 CalculateBezierPointForCubic(double t, Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
        {
            var point = new Vector2();

            var temp = 1 - t;
            point.X = (float)(p0.X * Math.Pow(temp, 3) + 3 * p1.X * t * Math.Pow(temp, 2) + 3 * p2.X * Math.Pow(t, 2) * temp + p3.X * Math.Pow(t, 3));
            point.Y = (float)(p0.Y * Math.Pow(temp, 3) + 3 * p1.Y * t * Math.Pow(temp, 2) + 3 * p2.Y * Math.Pow(t, 2) * temp + p3.Y * Math.Pow(t, 3));
            return point;
        }

        public double GetBezierLength(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
        {
            double pointCount = 30;
            double length = 0;
            Vector2 lastPoint = CalculateBezierPointForCubic(0.0 / pointCount, p0, p1, p2, p3);

            for (double i = 1; i <= pointCount; i++)
            {
                Vector2 point = CalculateBezierPointForCubic(i / pointCount, p0, p1, p2, p3);
                length += Math.Sqrt(Math.Pow(point.X - lastPoint.X, 2) + Math.Pow(point.Y - lastPoint.Y, 2));
                lastPoint = point;
            }

            return length;

        }

    }

}
